"""
配置管理模块
负责加载、验证和管理应用配置
"""

import logging
import os
from dataclasses import dataclass, field
from pathlib import Path
from typing import Dict, List, Any, Optional

import yaml

logger = logging.getLogger(__name__)


@dataclass
class ServerConfig:
    """服务器配置"""
    host: str = "0.0.0.0"
    port: int = 8001
    debug: bool = False


@dataclass
class AudioConfig:
    """音频配置"""
    sample_rate: int = 16000
    channels: int = 1
    segment_duration: float = 3.0
    volume_threshold: float = 0.01
    max_audio_duration: int = 300


@dataclass
class ModelConfig:
    """ASR模型配置"""
    model_dir: str = "./models/asr/sherpa-onnx-paraformer-zh-2024-03-09"
    tokens_file: str = "tokens.txt"
    model_file: str = "model.int8.ort"
    num_threads: int = 2
    feature_dim: int = 80
    decoding_method: str = "greedy_search"


@dataclass
class ASRConfig:
    """ASR识别配置"""
    recognition_timeout: int = 30
    max_retries: int = 3
    model: ModelConfig = field(default_factory=ModelConfig)


@dataclass
class LoggingConfig:
    """日志配置"""
    level: str = "INFO"
    format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"


@dataclass
class UploadConfig:
    """文件上传配置"""
    max_file_size: int = 50  # MB
    allowed_formats: List[str] = field(default_factory=lambda: ["wav", "mp3", "m4a", "flac", "ogg"])


@dataclass
class VADConfig:
    """VAD配置"""
    model_path: str = "models/vad/silero_vad.onnx"


@dataclass
class AppConfig:
    """应用总配置"""
    server: ServerConfig = field(default_factory=ServerConfig)
    audio: AudioConfig = field(default_factory=AudioConfig)
    asr: ASRConfig = field(default_factory=ASRConfig)
    vad: VADConfig = field(default_factory=VADConfig)
    logging: LoggingConfig = field(default_factory=LoggingConfig)
    upload: UploadConfig = field(default_factory=UploadConfig)


class ConfigManager:
    """配置管理器"""
    
    def __init__(self, config_file: Optional[str] = None):
        self.config_file = config_file or "config/config.yaml"
        self.config: Optional[AppConfig] = None
        
    def load_config(self) -> AppConfig:
        """加载配置文件"""
        config_path = Path(self.config_file)
        
        if not config_path.exists():
            logger.warning(f"配置文件不存在: {config_path}，使用默认配置")
            self.config = AppConfig()
            self._save_default_config(config_path)
            return self.config
        
        try:
            with open(config_path, 'r', encoding='utf-8') as f:
                config_data = yaml.safe_load(f)
            
            self.config = self._parse_config(config_data)
            self._validate_config()
            
            logger.info(f"配置文件加载成功: {config_path}")
            return self.config
            
        except Exception as e:
            logger.error(f"加载配置文件失败: {e}，使用默认配置")
            self.config = AppConfig()
            return self.config
    
    def _parse_config(self, config_data: Dict[str, Any]) -> AppConfig:
        """解析配置数据"""
        config = AppConfig()
        
        # 解析服务器配置
        if 'server' in config_data:
            server_data = config_data['server']
            config.server = ServerConfig(
                host=server_data.get('host', config.server.host),
                port=server_data.get('port', config.server.port),
                debug=server_data.get('debug', config.server.debug)
            )
        
        # 解析音频配置
        if 'audio' in config_data:
            audio_data = config_data['audio']
            config.audio = AudioConfig(
                sample_rate=audio_data.get('sample_rate', config.audio.sample_rate),
                channels=audio_data.get('channels', config.audio.channels),
                segment_duration=audio_data.get('segment_duration', config.audio.segment_duration),
                volume_threshold=audio_data.get('volume_threshold', config.audio.volume_threshold),
                max_audio_duration=audio_data.get('max_audio_duration', config.audio.max_audio_duration)
            )
        
        # 解析ASR配置
        if 'asr' in config_data:
            asr_data = config_data['asr']
            
            # 解析模型配置
            model_config = ModelConfig()
            if 'model' in asr_data:
                model_data = asr_data['model']
                model_config = ModelConfig(
                    model_dir=model_data.get('model_dir', model_config.model_dir),
                    tokens_file=model_data.get('tokens_file', model_config.tokens_file),
                    model_file=model_data.get('model_file', model_config.model_file),
                    num_threads=model_data.get('num_threads', model_config.num_threads),
                    feature_dim=model_data.get('feature_dim', model_config.feature_dim),
                    decoding_method=model_data.get('decoding_method', model_config.decoding_method)
                )
            
            config.asr = ASRConfig(
                recognition_timeout=asr_data.get('recognition_timeout', config.asr.recognition_timeout),
                max_retries=asr_data.get('max_retries', config.asr.max_retries),
                model=model_config
            )
        
        # 解析VAD配置
        if 'vad' in config_data:
            vad_data = config_data['vad']
            config.vad = VADConfig(
                model_path=vad_data.get('model_path', config.vad.model_path)
            )
        
        # 解析日志配置
        if 'logging' in config_data:
            logging_data = config_data['logging']
            config.logging = LoggingConfig(
                level=logging_data.get('level', config.logging.level),
                format=logging_data.get('format', config.logging.format)
            )
        
        # 解析上传配置
        if 'upload' in config_data:
            upload_data = config_data['upload']
            config.upload = UploadConfig(
                max_file_size=upload_data.get('max_file_size', config.upload.max_file_size),
                allowed_formats=upload_data.get('allowed_formats', config.upload.allowed_formats)
            )
        
        return config
    
    def _validate_config(self):
        """验证配置参数"""
        if not self.config:
            return
        
        # 验证服务器配置
        if not (1 <= self.config.server.port <= 65535):
            raise ValueError(f"无效的端口号: {self.config.server.port}")
        
        # 验证音频配置
        if self.config.audio.sample_rate <= 0:
            raise ValueError(f"无效的采样率: {self.config.audio.sample_rate}")
        
        if self.config.audio.channels not in [1, 2]:
            raise ValueError(f"不支持的声道数: {self.config.audio.channels}")
        
        # 验证ASR配置
        if self.config.asr.recognition_timeout <= 0:
            raise ValueError(f"无效的识别超时时间: {self.config.asr.recognition_timeout}")
        
        logger.info("配置验证通过")
    
    def _save_default_config(self, config_path: Path):
        """保存默认配置文件"""
        try:
            default_config = {
                'server': {
                    'host': '0.0.0.0',
                    'port': 8001,
                    'debug': False
                },
                'audio': {
                    'sample_rate': 16000,
                    'channels': 1,
                    'segment_duration': 3.0,
                    'volume_threshold': 0.01,
                    'max_audio_duration': 300
                },
                'asr': {
                    'recognition_timeout': 30,
                    'max_retries': 3,
                    'model': {
                        'model_dir': './models/asr/sherpa-onnx-paraformer-zh-2024-03-09',
                        'tokens_file': 'tokens.txt',
                        'model_file': 'model.int8.ort',
                        'num_threads': 2,
                        'feature_dim': 80,
                        'decoding_method': 'greedy_search'
                    }
                },
                'vad': {
                    'model_path': 'models/vad/silero_vad.onnx'
                },
                'logging': {
                    'level': 'INFO',
                    'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
                },
                'upload': {
                    'max_file_size': 50,
                    'allowed_formats': ['wav', 'mp3', 'm4a', 'flac', 'ogg']
                }
            }
            
            with open(config_path, 'w', encoding='utf-8') as f:
                yaml.dump(default_config, f, default_flow_style=False, allow_unicode=True)
            
            logger.info(f"默认配置文件已保存: {config_path}")
            
        except Exception as e:
            logger.error(f"保存默认配置文件失败: {e}")
    
    def get_config(self) -> AppConfig:
        """获取配置"""
        if self.config is None:
            self.load_config()
        return self.config
    
    def reload_config(self) -> AppConfig:
        """重新加载配置"""
        return self.load_config()


# 全局配置管理器实例
config_manager = ConfigManager()


def get_config() -> AppConfig:
    """获取应用配置"""
    return config_manager.get_config()


def reload_config() -> AppConfig:
    """重新加载配置"""
    return config_manager.reload_config()
